#include "MQTTFunc.h"
 
const char* ssid="iphone";//WIFI名称
const char* password="12345678";//WIFI密码
const char* mqtt_server = "183.230.40.96"; //onenet 的 IP地址 mqtts.heclouds.com 183.230.40.96
const int port = 1883; //端口号(未加密接入)    

#define RELAY_PIN 37 // 继电器连接的Arduino引脚 


char msg_buf[200];
//发送信息缓冲区

char msgJson[75];    
unsigned short json_len = 0;   
#define mqtt_pubid "4MLdrQTupB"    //产品ID
//鉴权信息
#define  mqtt_devid  "000000011"

#define mqtt_password "version=2018-10-31&res=products%2F4MLdrQTupB&et=1964404427&method=md5&sign=IyVjNjMt0u29xQQcKgw1SQ%3D%3D"


// int postMsgId = 0; //记录已经post了多少条
//----------------------------------------------------------------------------
//设备上传数据的post主题
#define ONENET_TOPIC_PROP_POST "$sys/" mqtt_pubid "/" mqtt_devid "/dp/post/json" 
//接收下发属性设置主题
#define ONENET_TOPIC_PROP_SET  "$sys/" mqtt_pubid "/" mqtt_devid "/dp/post/json/+" //"$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/set"
//接收下发属性设置成功的回复主题
#define ONENET_TOPIC_PROP_SET_REPLY "$sys/" mqtt_pubid "/" mqtt_devid "/dp/post/accepted" //"$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/set_reply"
 
//接收设备属性获取命令主题
//#define ONENET_TOPIC_PROP_GET "$sys/" mqtt_pubid "/" mqtt_devid "/cmd/request/+" //"$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/get"
#define ONENET_TOPIC_PROP_GET "$sys/" mqtt_pubid "/" mqtt_devid "/cmd/request/+"
//接收设备属性获取命令成功的回复主题
#define ONENET_TOPIC_PROP_GET_REPLY "$sys/" mqtt_pubid "/" mqtt_devid "/cmd/response/+/+" //"$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/get_reply"
 
//这是post上传数据使用的模板
#define ONENET_POST_BODY_FORMAT "{\"id\":%d,\"dp\":%s}"
//----------------------------------------------------------------------------



//连接WIFI相关函数
void MQTTFunc::setupWifi(void)
{
  delay(10);
//  Serial.println("connect WIFI");
  WiFi.begin(ssid, password);
  while (!WiFi.isConnected())
  {
//    Serial.print(".");
    delay(500);
  }
//  Serial.println("OK");
//  Serial.println("Wifi connected!");
//  Serial.println("IP address: ");
//  Serial.println(WiFi.localIP());

}

void MQTTFunc::SendString(String str)
{
  if (client->connected())
  {
    if ((str.length() > 0)  ) {
        str = "\"" + str + "\"";
      char rx_buffer[str.length() + 1];
      str.toCharArray(rx_buffer, str.length() + 1);
      //先拼接出json字符串
      char param[256];
      char jsonBuf[280];
      sprintf(param, "{ \"data\":[{\"v\":%s}]}",rx_buffer); //我们把要上传的数据写在param里  
      postMsgId += 1;
      sprintf(jsonBuf, ONENET_POST_BODY_FORMAT, postMsgId, param);
      //再从mqtt客户端中发布post消息
      if (client->publish(ONENET_TOPIC_PROP_POST, jsonBuf))
      {
         Serial.print("Post message to cloud: ");
         Serial.println(jsonBuf);
      }
      else
      {
    //      Serial.println("Publish message to cloud failed!");
      }
    }
  }
}

String MQTTFunc::DecodeSensorData2JsonString(SensorData data)
{
  String Data = "{"
                "\"Depth\":" + String(data.Depth) + "," +
                "\"COD_Val\":" + String(data.COD_Val) + "," +
                "\"COD_Temp\":" + String(data.COD_Temp) + "," +
                "\"COD_PH\":" + String(data.COD_PH) + "," +
                "\"DO_Perc\":" + String(data.DO_Perc) + "," +
                "\"DO_Val\":" + String(data.DO_Val) + "," +
                "\"DO_PH\":" + String(data.DO_PH) + "," +
                "\"DO_Temp\":" + String(data.DO_Temp) +
                "}";
  return Data;
}

// void MQTTFunc::sendTempAndHumi(void)
// {
//   if (client.connected())
//   {

//     if ((Serial.available() > 0)  ) {
//       String data = Serial.readString();
//         String str= "\"" + data + "\"";
//       char rx_buffer[str.length() + 1];
//       str.toCharArray(rx_buffer, str.length() + 1);
//       //先拼接出json字符串
//       char param[180];
//       char jsonBuf[200];
//       sprintf(param, "{ \"data\":[{\"v\":%s}]}",rx_buffer); //我们把要上传的数据写在param里
//       postMsgId += 1;
//       sprintf(jsonBuf, ONENET_POST_BODY_FORMAT, postMsgId, param);
//       //再从mqtt客户端中发布post消息
//       if (client.publish(ONENET_TOPIC_PROP_POST, jsonBuf))
//       {
//     //      Serial.print("Post message to cloud: ");
//     //      Serial.println(jsonBuf);
//       }
//       else
//       {
//     //      Serial.println("Publish message to cloud failed!");
//       }
//     }
//   }
// }


//重连函数, 如果客户端断线,可以通过此函数重连
void MQTTFunc::clientReconnect(void)
{
  while (!client->connected()) //再重连客户端
  {
//    Serial.println("reconnect MQTT...");
    if ( client->connect(mqtt_devid, mqtt_pubid, mqtt_password) )
    {
//      Serial.println("connected");
    }
    else
    {
//      Serial.println("failed");
//      Serial.println(client.state());
//      Serial.println("try again in 5 sec");
      delay(5000);
    }
  }
}


void MQTTFunc::init(std::function<void(char*, unsigned char*, unsigned int)> DecodeDataFunc, void (* SendDataFunc)(void) )
{
    client = new PubSubClient(espClient);
    delay(3000);
    setupWifi();                                           //调用函数连接WIFI
    client->setServer(mqtt_server, port);                   //设置客户端连接的服务器,连接Onenet服务器, 使用1883端口
    delay(2000);
    //Serial.println("setServer Init!");
    //client.setCallback(callback);
    client->connect(mqtt_devid, mqtt_pubid, mqtt_password); //客户端连接到指定的产品的指定设备.同时输入鉴权信息
    delay(2000);
    if (client->connected())
    {
     Serial.println("OneNet is connected!"); //判断以下是不是连好了.
    }
  //  client.subscribe(ONENET_TOPIC_PROP_SET);
    client->subscribe(ONENET_TOPIC_PROP_GET);
    client->setCallback(DecodeDataFunc);
    tim1.attach(10, SendDataFunc); //定时每2秒调用一次发送数据函数sendTempAndHumi
}

MQTTFunc::MQTTFunc()
{
  client =nullptr;
}

MQTTFunc::~MQTTFunc()
{
  if (client != nullptr)
  {
    delete client;
  }
}

void MQTTFunc::checkWIFI(void)
{
    if (!WiFi.isConnected()) //先看WIFI是否还在连接
    {
        setupWifi();
    }
}

void MQTTFunc::checkConnect(void)
{
    if (!client->connected()) //如果客户端没连接ONENET, 重新连接
    {
        clientReconnect();
        delay(100);
    }
    client->loop(); //客户端循环检测
}
